<script setup lang="ts">
import { ref, reactive, computed, watchEffect, defineAsyncComponent, onMounted, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { useQuestionItem, useClearQuestionItem, useCourseChapter } from './question-hook'
import { questionTypeOptions, RADIO, CHECKBOX, TRUE_FALSE, FILL_BLANK, ESSAY, COMPOSITE } from '../const'
import { createExamQuestionApi, updateExamQuestionApi } from "#/api/manage/question-bank"
import { obsUpload } from "#/utils/obs"
import { cloneDeep } from '@vben/utils'
import { safeMergeObject } from '#/utils/objectMerge'
import { getImgUrl } from "#/utils/getImgUrl"
import { $t } from '@vben/locales';
import { isWangEditorEmpty } from '#/utils/editorUtils'
import { isValidJSON } from '#/utils/isValidJSON'

// 动态导入所有题目组件
const components = {
  [RADIO]: defineAsyncComponent(() => import('./components/radio.vue')),
  [CHECKBOX]: defineAsyncComponent(() => import('./components/checkbox.vue')),
  [TRUE_FALSE]: defineAsyncComponent(() => import('./components/true-false.vue')),
  [FILL_BLANK]: defineAsyncComponent(() => import('./components/fill-blank.vue')),
  [ESSAY]: defineAsyncComponent(() => import('./components/essay.vue')),
  [COMPOSITE]: defineAsyncComponent(() => import('./components/composite.vue'))
} as const

defineOptions({ name: 'Drawer' })
const emit = defineEmits(['queryData'])

const submitLoading = ref(false)
const editVisible = ref(false)
const title = ref($t('questionBank.addQuestion'))
const createQuestionRef = ref<any>(null)
const formRef = ref()
const componentName = computed(() => components[queryData.type as keyof typeof components])
type optionType = {
  name: string//选项的名称，A,B,C,D默认
  content: string//选项的内容 比如A对应的内容是什么
  file?: any//选项的图片文件
  path?: string//选项的图片路径
  url?: string//选项的图片url
}

interface QuestionData {
  type: string//题目类型
  stem: string//题目
  stemImg: string//题目图片
  answers: string | string[]//答案
  analysis: string
  options: optionType[] | string
  id?: string//题目id
  courseId: string | undefined//课程id
  chapterId: string | undefined//章节id
  stemImages?: any[]
}

const initData = {
  type: RADIO,
  stem: '',
  stemImg: '',
  answers: [],
  analysis: '',
  options: [],
  courseId: undefined,
  chapterId: undefined,
  stemImages: []
}
const queryData = reactive<QuestionData>(cloneDeep(initData))
const question = useQuestionItem()
const isEdit = computed(() => question.value?.type)

// 使用共享的课程章节 hooks
const { 
  courseOptions, 
  chapterOptions, 
  courseLoading, 
  chapterLoading, 
  getCourseInfo, 
  handleCourseChange: handleCourseChangeBase,
  clearCourseChapterData 
} = useCourseChapter()

const handleCourseChange = (value: string) => {
  queryData.chapterId = undefined
  handleCourseChangeBase(value)
}
const handleChapterChange = (value: string) => {
  // 章节变化处理逻辑
}

const rules = {
  type: [{ required: true, message: $t('common.selectPhTxt', [$t('questionBank.questionType')]), trigger: 'change' }],
  stem: [{
    required: true,
    validator: (rule: any, value: any, callback: any) => {
      try {
        // 使用工具函数检查wangEditor内容是否为空
        if (isWangEditorEmpty(value)) {
          callback(new Error($t('common.requiredTxt', [$t('questionBank.question')])))
        } else {
          callback()
        }
      } catch (error) {
        callback()
      }
    },
    trigger: 'blur'
  }],
  answers: [{ required: true, message: $t('common.requiredTxt', [$t('questionBank.referenceAnswer')]), trigger: 'blur' }],
  options: [{
    required: true,
    validator: (rule: any, value: any, callback: any) => {
      try {
        if (!Array.isArray(value)) {
          callback(new Error($t('questionBank.optionsFormatError')))
          return
        }
        if (queryData.type === RADIO || queryData.type === CHECKBOX) {
          const os = value.some((s: any) => !s.content && !s.path)
          if (os) {
            callback(new Error($t('common.requiredTxt', [$t('questionBank.questionOptions') + '内容'])))
          } else {
            callback()
          }
        } else if (queryData.type === TRUE_FALSE) {
          const os = value.some((s: any) => !s.name)
          if (os) {
            callback(new Error($t('common.requiredTxt', [$t('questionBank.questionOptions') + '内容'])))
          } else {
            callback()
          }
        } else if (queryData.type === FILL_BLANK) {
          const os = value.some((s: any) => !s)
          if (os) {
            callback(new Error($t('questionBank.fillBlankAnswerRequired')))
          } else {
            callback()
          }
        } else {
          callback()
        }
      } catch (error) {
        callback()
      }
    },
    trigger: 'blur'
  }],
  courseId: [{ required: true, message: $t('common.selectPhTxt', [$t('course.course')]), trigger: 'change' }],
  chapterId: [{ required: true, message: $t('common.selectPhTxt', [$t('course.chapter')]), trigger: 'change' }]
}

const getStemImgsBlob = async (path: string) => {
  if (!path) return null
  return new Promise(async (resolve) => {
    const imgData = await getImgUrl(path)
    if (imgData instanceof ArrayBuffer) {
      const blob = new Blob([imgData], { type: 'image/png' })
      resolve(blob)
    }
    resolve(null)
  })
}

const handleStemImgs = async (stemImgs: string[]) => {
  if (!stemImgs.length) return []
  return new Promise(async (resolve, reject) => {
    const imageList: any = []
    for (const stemImg of stemImgs) {
      const blob = await getStemImgsBlob(stemImg)
      if (blob instanceof Blob) {
        imageList.push({
          file: blob,
          path: stemImg,
          url: URL.createObjectURL(blob),
          name: stemImg,
        })
      }
    }
    resolve(imageList)
  })
}

// 使用 watch 替代 watchEffect 避免重复执行
let isProcessing = false // 防止重复处理
watch(() => question.value, async (newQuestion) => {
  if (isProcessing) return // 如果正在处理，直接返回
  
  if (isEdit.value && newQuestion) {
    isProcessing = true
    try {
      title.value = $t('questionBank.editQuestion')
      editVisible.value = true
      let editData = cloneDeep(initData) as any
      
      // 防护：确保courseId存在，先处理课程章节数据
      if (newQuestion?.courseId) {
        handleCourseChange(newQuestion.courseId)
      }

      safeMergeObject(editData, cloneDeep(newQuestion || {}))
      let { type = '', answers, stemImg = '', options } = editData
      
      // 处理图片数据
      if (stemImg && typeof stemImg === 'string') {
        editData.stemImages = await handleStemImgs(stemImg.split(',').filter(Boolean))
      } else {
        editData.stemImages = []
      }

      // 处理选项图片，需要等待所有异步操作完成
      if (options && Array.isArray(options) && options.length) {
        for (const item of options) {
          if (item?.path) {
            try {
              const blob = await getStemImgsBlob(item.path)
              if (blob instanceof Blob) {
                item.url = URL.createObjectURL(blob)
                item.file = blob
              }
            } catch (error) {
              // 下载选项图片失败，静默处理
            }
          }
        }
      }

      // 处理answers数据
      try {
        switch (type) {
          case RADIO:
            editData.answers = (JSON.parse(answers || '[]') ?? []).map((m: any) => m.name).join()
            break;
          case TRUE_FALSE:
            editData.answers = JSON.parse(answers || '{}')?.name || ''
            break;
          case ESSAY:
            editData.answers = answers || ''
            break;
          case CHECKBOX:
            editData.answers = JSON.parse(answers || '[]').map((item: any) => item.name) || []
            break;
          case FILL_BLANK:
            editData.answers = isValidJSON(answers) ? JSON.parse(answers) : answers || []
            break;
          default:
            break;
        }
      } catch (error) {
        // JSON解析失败，使用默认值
        editData.answers = type === CHECKBOX || type === FILL_BLANK ? [] : ''
      }

      // 最后一次性更新所有数据
      Object.assign(queryData, editData)
      editVisible.value = false
    } catch (error) {
      editVisible.value = false
      // 编辑数据处理失败，静默处理
    } finally {
      isProcessing = false
    }
  } else {
    title.value = $t('questionBank.addQuestion')
  }
}, { 
  immediate: true, 
  deep: true // 深度监听question对象的变化
})

// 监听题目类型变化，重置相关数据
const handleTypeChange = (newType: string) => {
  if (!isEdit.value) {
    // 保存当前的题目、解析和图片数据
    const preservedStem = queryData.stem
    const preservedAnalysis = queryData.analysis
    const preservedStemImages = queryData.stemImages
    const preservedCourseId = queryData.courseId
    const preservedChapterId = queryData.chapterId
    // resetFormData()
    // 根据题目类型重置 answers 字段的数据类型
    switch (newType) {
      case RADIO:
      case TRUE_FALSE:
      case ESSAY:
        queryData.answers = ''
        break
      case CHECKBOX:
      case FILL_BLANK:
        queryData.answers = []
        break
      default:
        queryData.answers = ''
        break
    }
    //只重置选项数据，保留其他数据
    queryData.options = []
    // 恢复保存的数据
    queryData.stem = preservedStem
    queryData.analysis = preservedAnalysis
    queryData.stemImages = preservedStemImages
    queryData.courseId = preservedCourseId
    queryData.chapterId = preservedChapterId
  }
}
const drawerVisible = ref(false)
// 重置表单数据
const resetFormData = () => {
  safeMergeObject(queryData, cloneDeep(initData))
  useClearQuestionItem()
  clearCourseChapterData()
  queryData.chapterId = undefined
  queryData.courseId = undefined
}
const handleClose = () => {
  drawerVisible.value = false
  resetFormData()
}
const init = () => {
  drawerVisible.value = true
}

const validate = () => {
  return new Promise((resolve, reject) => {
    try {
      if (!formRef.value) {
        reject(false)
        return
      }
      formRef.value.validate((valid: Boolean) => {
        resolve(valid)
      })
    } catch (error) {
      reject(false)
    }
  })
}

const uploadToOBS = (Key: string, file: any): Promise<string> => {
  return new Promise((resolve, reject) => {
    obsUpload({
      Key,
      SourceFile: file
    }, (err: any, result: any, key: string) => {
      if (err) {
        reject(err)
        return
      }
      // 返回文件URL，根据实际OBS配置调整
      resolve(key)
    })
  })
}

const uploadOptionsToOBS = async (options: optionType[]): Promise<string[]> => {
  const uploadPromises = options.map(async (option) => {
    if (option.file && option.path) {
      try {
        const result = await uploadToOBS(option.path, option.file)
        return result
      } catch (error) {
        throw error
      }
    }
    return '' // 如果没有文件，返回空字符串
  })
  return Promise.all(uploadPromises)
}

const submit = async () => {
  const valid = await validate()
  if (!valid) return
  submitLoading.value = true
  let api = createExamQuestionApi
  let params = cloneDeep(queryData) as any // 使用 any 类型来避免类型检查冲突
  let { stemImages = [], options = [], type } = params
  // 处理题目图片，上传新图片并整合所有图片路径到 stemImg 字段
  if (stemImages?.length) {
    try {
      const imagePaths = await uploadOptionsToOBS(stemImages)
      // 过滤掉空字符串，获取所有有效的文件路径
      const validPaths = imagePaths.filter(path => !!path)
      // 将所有有效路径用逗号连接，并赋值给 stemImg
      params.stemImg = validPaths.join(',')
      delete params.stemImages
    } catch (error) {
      ElMessage.error($t('common.uploadFailTxt'));
      return; // 中断提交
    }
  }
  if (params.stemImages) {
    delete params.stemImages
  }
  // 处理选项图片，上传新图片并更新路径
  if (Array.isArray(options) && options.length) {
    try {
      for (const option of options as optionType[]) {
        if (option?.file && option?.path) {
          const result = await uploadToOBS(option.path, option.file)
          // 更新选项的path为OBS返回的key
          option.path = result
          // 清除file字段，避免序列化问题
          delete option.file
          delete option.url
        }
      }
    } catch (error) {
      ElMessage.error($t('common.uploadFailTxt'))
      submitLoading.value = false
      return // 中断提交
    }
  }
  try {
    // 将选项转换为JSON字符串
    if (![FILL_BLANK, ESSAY].includes(type)) {
      params.options = JSON.stringify(params.options)
    } else {
      if (params.options) {
        delete params.options
      }
    }
    switch (type) {
      case RADIO:
        params.answers = JSON.stringify([{ name: params.answers }])
        break;
      case TRUE_FALSE:
        params.answers = JSON.stringify({ name: params.answers })
        break;
      case ESSAY:
        break;
      case CHECKBOX:
        params.answers = JSON.stringify(params.answers.map((item: any) => ({ name: item })))
        break;
      case FILL_BLANK:
        params.answers = JSON.stringify(params.answers)
        break;
      default:
        break;
    }
    if (isEdit.value) {
      api = updateExamQuestionApi
      params.id = question.value?.id ?? ''
    }

    await api(params).then(() => {
      ElMessage.success($t('questionBank.saveSuccess'))
      // drawerVisible.value = false
      handleClose()
      emit('queryData')
    })
  } catch (error) {
    ElMessage.error($t('questionBank.saveFailed'))
  } finally {
    submitLoading.value = false
  }
}

watch(() => drawerVisible.value, (newVal) => {
  if (newVal) {
    getCourseInfo()
  } else {
    resetFormData()
  }
})

defineExpose({
  init
})
</script>

<template>
  <el-drawer v-model="drawerVisible" :title="title" :size="1000" :close-on-click-modal="false" destroy-on-close
    :before-close="handleClose">
    <div class="p-[0px]">
      <el-form ref="formRef" :model="queryData" :rules="rules" label-width="auto" v-loading="editVisible">
        <el-row>
          <el-col :span="8">
            <el-form-item :label="$t('questionBank.questionType')" prop="type">
              <el-select v-model="queryData.type" :placeholder="$t('common.selectPhTxt', [$t('questionBank.questionType')])" style="width: 200px" :disabled="!!isEdit"
                @change="handleTypeChange">
                <el-option v-for="item in questionTypeOptions" :key="item.value" :label="item.label"
                  :value="item.value" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item :label="$t('course.course')" prop="courseId">
              <el-select v-model="queryData.courseId" :placeholder="$t('common.selectPhTxt', [$t('course.course')])" style="width: 300px" :disabled="!!isEdit"
                @change="handleCourseChange">
                <el-option v-for="item in courseOptions" :key="item.value" :label="item.label" :value="item.value" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item :label="$t('course.chapter')" prop="chapterId">
              <el-select v-model="queryData.chapterId" :placeholder="$t('common.selectPhTxt', [$t('course.chapter')])" style="width: 300px" :disabled="!!isEdit"
                @change="handleChapterChange">
                <el-option v-for="item in chapterOptions" :key="item.value" :label="item.label" :value="item.value" />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <component :is="componentName" ref="createQuestionRef" v-model="queryData"
          :key="`${queryData.type}-${isEdit ? 'edit' : 'new'}`">
        </component>
      </el-form>
    </div>


    <template #footer>
      <div class="dialog-footer">
        <el-button @click="drawerVisible = false">{{ $t('common.cancelTxt') }}</el-button>
        <el-button type="primary" @click="submit" :loading="submitLoading" class="w-[80px]">
          {{ $t('questionBank.confirm') }}
        </el-button>
      </div>
    </template>
  </el-drawer>
</template>
<style lang="css" scoped>
.el-form-item__content {
  width: 100%;
}
</style>
